package com.ciaojian.worker.service;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ciaojian.core.constant.RedisConstant;
import com.ciaojian.core.enums.business.LeaveDetailType;
import com.ciaojian.core.enums.business.ScheduleTypeEnum;
import com.ciaojian.core.enums.business.WorkerApplyStatusEnum;
import com.ciaojian.core.mapper.*;
import com.ciaojian.core.model.*;
import com.ciaojian.core.model.vo.CheckUser;
import com.ciaojian.core.model.vo.RosterWorkerTimeVo;
import com.ciaojian.core.service.SchedulingService;
import com.ciaojian.core.util.DateUtil;
import com.ciaojian.core.util.LogUtil;
import com.ciaojian.core.util.Result;
import com.ciaojian.core.util.TimeUtil;
import com.ciaojian.miniapp.api.WxMiniAppApi;
import com.ciaojian.miniapp.model.request.AccessToken;
import com.ciaojian.miniapp.model.request.submessage.AuditScheduleMessage;
import com.ciaojian.miniapp.model.request.submessage.BaseTemplate;
import com.ciaojian.miniapp.model.request.submessage.TemplateIdEnum;
import com.ciaojian.miniapp.model.response.SubMessageSendResponse;
import com.ciaojian.worker.model.param.LeaveApplyParam;
import com.ciaojian.worker.model.query.SchedulingApplyQuery;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


/**
 * @author Atlakyn
 */
@Service
public class SchedulingServiceImpl extends SchedulingService<SchedulingMapper, Scheduling> implements IService<Scheduling> {
    @Resource
    private RedisTemplate<String, List<CheckUser>> redisTemplate;
    @Resource
    private StoreDinnerTimeServiceImpl storeDinnerTimeService;
    @Resource
    private WorkerApplyServiceImpl workerApplyService;
    @Resource
    private WorkerMapper workerMapper;
    @Resource
    private SchedulingMapper schedulingMapper;
    @Resource
    private SchedulingExamineMapper schedulingExamineMapper;
    @Resource
    private RosterMapper rosterMapper;

    /**
     * 查询时间段内发型师的排班
     *
     * @param workerId 发型师
     * @param begin    开始时间
     * @param end      结束时间
     * @return 时间段内发型师的排班
     */
    public List<Scheduling> listBetweenDate(Integer workerId, Date begin, Date end) {
        return this.lambdaQuery()
                .between(Scheduling::getDate, begin, end)
                .eq(Scheduling::getWorkerId, workerId)
                .list();
    }


    /**
     * 提交排班申请
     *
     * @param schedulingApplyBO 提交排班参数
     * @return 新增成功返回 true
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean apply(SchedulingApplyQuery schedulingApplyBO) {
        // 判断是否还有正在审核的排班申请
        LambdaQueryWrapper<SchedulingExamine> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SchedulingExamine::getWid, schedulingApplyBO.getWorkerId())
                .in(SchedulingExamine::getStatus, WorkerApplyStatusEnum.WAIT)
                .eq(SchedulingExamine::getLogicDel, Boolean.FALSE);
        Integer selectCount = new SchedulingExamine().selectCount(queryWrapper);
        Assert.isTrue(selectCount == 0, "您当前已有排班申请待审核");
        Assert.isTrue(schedulingApplyBO.getSchedulingList().size()!=0, "请填入排班信息");

        Worker worker = new Worker().selectById(schedulingApplyBO.getWorkerId());

        //排班信息
        SchedulingExamine schedulingExamine = new SchedulingExamine();

        schedulingExamine.setStoreId(schedulingApplyBO.getStoreId());
        schedulingExamine.setStoreName(schedulingApplyBO.getStoreName());
        schedulingExamine.setPhone(worker.getTelphone());
        schedulingExamine.setName(worker.getName().concat(" 提交了班表"));
        schedulingExamine.setStatus(WorkerApplyStatusEnum.WAIT);
        schedulingExamine.setWid(schedulingApplyBO.getWorkerId());
        schedulingExamine.setBeginDate(schedulingApplyBO.getBeginDate());
        schedulingExamine.setEndDate(schedulingApplyBO.getEndDate());
        schedulingExamine.insert();

//        schedulingExamine = schedulingExamineMapper.insertExamine(schedulingExamine);

        int count =0;

        //请假信息
        LeaveApplyParam param = new LeaveApplyParam();
        param.setStoreName(schedulingApplyBO.getStoreName());
        param.setType(LeaveDetailType.PERSONAL_LEAVE);

        List<Scheduling> schedulingList = schedulingApplyBO.getSchedulingList();
        for (Scheduling scheduling : schedulingList) {
            Scheduling schedulingOld = new Scheduling();
            try {
                schedulingOld = getSchedulingDroster(scheduling.getWorkerId(), scheduling.getDate());
            }catch (Exception e){

            }

            if (ObjectUtil.isNotNull(schedulingOld)){
                continue;
            }

            //请假
            if (scheduling.getRosterId()==1){
                scheduling.setType(ScheduleTypeEnum.WORK);
                scheduling.setExamineId(schedulingExamine.getId());
                //插入请假排班
                int insert = schedulingMapper.insert(scheduling);
                //提交请假申请
                if(insert>0) {
                    param.setWorkerId(scheduling.getWorkerId());
                    param.setWorkerName(scheduling.getName());
                    param.setStoreId(scheduling.getStoreId());
                    param.setBeginDate(scheduling.getDate());
                    param.setEndDate(scheduling.getDate());

                    workerApplyService.leaveApply(param);
                }

            }else {
                //排班
                if (count == 0) {
                    count++;
                }
                scheduling.setExamineId(schedulingExamine.getId());
                if (scheduling.getRosterId()!=-1 && scheduling.getRosterId()!=1) {
                    Roster roster = rosterMapper.selectById(scheduling.getRosterId());
                    scheduling.setLunchStartTime(roster.getLunchStartTime());
                    scheduling.setLunchStartTime(roster.getLunchEndTime());
                    scheduling.setDinnerStartTime(roster.getDinnerStartTime());
                    scheduling.setDinnerEndTime(roster.getDinnerEndTime());
                }
                schedulingMapper.insert(scheduling);
            }
        }

        if(count>0) {
            // 发送通知
            {
                AuditScheduleMessage messageData = AuditScheduleMessage.builder()
                        .thing1("排班审核")
                        .thing2(schedulingApplyBO.getStoreName())
                        .thing9(String.valueOf(schedulingApplyBO.getWorkerId()))
                        .time10(DateUtil.now())
                        .time4(DateUtil.formatDateTime(schedulingApplyBO.getBeginDate()))
                        .build();
                List<String> openIds = Arrays.asList("oUrLI5b7pIMMQP07I49lfPpwPzfY", "oUrLI5UAvnlYs_PKGem-nJK_grlw");
                openIds.forEach(openId -> {
                    BaseTemplate auditScheduleMessage = BaseTemplate.builder(TemplateIdEnum.AUDIT_SCHEDULE_MESSAGE)
                            .touser(openId)
                            .data(messageData);
                    try {
                        AccessToken accessToken = new AccessToken();
                        accessToken.setAppid("wx49b135179c539cde");
                        accessToken.setSecret("2e1d55e733cea4c47c507e15b349b993");
                        SubMessageSendResponse response = WxMiniAppApi.subscribeMessageSend(auditScheduleMessage, accessToken);
                        LogUtil.writeBusinessLog("排班发送通知返回结果:{}", response);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                        LogUtil.writeErrorLog(e.getMessage());
                    }
                });
            }
        }


        return true;
    }

    private Scheduling getSchedulingDroster(Integer workerId, Date date) {
        QueryWrapper<Scheduling> schedulingQueryWrapper = new QueryWrapper<>();
        schedulingQueryWrapper.eq("worker_id",workerId);
        schedulingQueryWrapper.eq("date",date);
        schedulingQueryWrapper.in("status",0,1);
        Scheduling scheduling = schedulingMapper.selectOne(schedulingQueryWrapper);
        return scheduling;
    }


    /**
     * 分配就餐时间
     *
     * @param workerId 分配的发型师ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void setupDinnerTime(Integer workerId) {
        Worker worker = new Worker().selectById(workerId);
        // 查询发型师当日排班
        Scheduling schedule = super.getWorkerScheduledToday(workerId);
        // 查询班次  上班时间是11点之前还是之后
        Roster roster = new Roster().selectById(schedule.getRosterId());
        // 查询Redis中同门店的打卡记录数
        Long size = redisTemplate.opsForList().size((RedisConstant.CLOCK_IN + worker.getStoreId()));

        // 门店就餐时间
        StoreDinnerTime storeDinnerTime = storeDinnerTimeService.getByStoreId(worker.getStoreId());
        Assert.notNull(storeDinnerTime, "门店就餐时间未设置");
        // 单数次
        if (size != null && size % 2 == 1) {
            // 午饭开始时间
            Time lunchTimeStart = storeDinnerTime.getLunchTimeStart();
            // 晚饭开始时间
            Time supperTimeStart = storeDinnerTime.getSupperTimeStart();
            // 分配就餐时间
            setupDinnerTime(roster, schedule, lunchTimeStart, supperTimeStart);
        }
        // 双数次
        if (size != null && size % 2 == 0) {
            // 午饭开始时间
            Time lunchTimeStart = storeDinnerTime.getLunchTimeMiddle();
            // 晚饭开始时间
            Time supperTimeStart = storeDinnerTime.getSupperTimeMiddle();
            // 分配就餐时间
            setupDinnerTime(roster, schedule, lunchTimeStart, supperTimeStart);
        }
        schedule.updateById();
    }

    /**
     * 分配就餐时间
     *
     * @param roster          班次
     * @param schedule        排班
     * @param lunchTimeStart  午餐开始时间
     * @param supperTimeStart 晚餐开始时间
     */
    private void setupDinnerTime(Roster roster, Scheduling schedule, Time lunchTimeStart, Time supperTimeStart) {
        // 轻餐-午餐 分割点
        Time checkTime = Time.valueOf("11:00:00");
        // 11点前上班
        if (roster.getStartWorkTime().compareTo(checkTime) < 0) {
            schedule.setLunchStartTime(new Time(lunchTimeStart.getTime()));
            schedule.setLunchEndTime(new Time(TimeUtil.offset(lunchTimeStart, 30).getTime()));
        }
        // 11点后上班
        if (roster.getStartWorkTime().compareTo(checkTime) > 0) {
            schedule.setLunchStartTime(new Time(lunchTimeStart.getTime()));
            schedule.setLunchEndTime(new Time(TimeUtil.offset(lunchTimeStart, 15).getTime()));
        }
        // 晚餐时间
        schedule.setDinnerStartTime(new Time(supperTimeStart.getTime()));
        schedule.setDinnerEndTime(new Time(TimeUtil.offset(supperTimeStart, 30).getTime()));
    }


    public Result delWorkerDate(Integer workerId, Date delDate) {
        try {
            QueryWrapper<Scheduling> schedulingQueryWrapper = new QueryWrapper<>();
            schedulingQueryWrapper.eq("worker_id",workerId);
            schedulingQueryWrapper.eq("date",delDate);
            schedulingQueryWrapper.eq("status",1);
            Scheduling scheduling = new Scheduling();
            scheduling.setStatus(WorkerApplyStatusEnum.DISMISSED);
            scheduling.setLogicDel(true);
            int update = schedulingMapper.update(scheduling, schedulingQueryWrapper);

            if (update>0){
                return Result.ok();
            }else {
                return Result.fail();
            }
        }catch (Exception e){
            return Result.fail();
        }
    }

    public RosterWorkerTimeVo getRosterWorkerTime(int workerId,String date){
        RosterWorkerTimeVo rosterWorkerTimeVo= schedulingMapper.getRosterWorkerTime(workerId,date);
        return rosterWorkerTimeVo;
    }


    public int getLeaveDays(int workerId,String date){
        return schedulingMapper.getLeaveDays(workerId,date);
    }
}
